home *** CD-ROM | disk | FTP | other *** search
/ Nautilus 1992 July / Nautilus-3-8 / Nautilus-3-8.bin / Tools & Utilities / Techy Stuff / Development Environments ƒ / Perl 4.0.2 ƒ / toke.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-01-14  |  56.3 KB  |  2,579 lines

  1. /* $RCSfile: toke.c,v $$Revision: 4.0.1.5 $$Date: 91/11/11 16:45:51 $
  2.  *
  3.  *    Copyright (c) 1991, Larry Wall
  4.  *
  5.  *    You may distribute under the terms of either the GNU General Public
  6.  *    License or the Artistic License, as specified in the README file.
  7.  *
  8.  * $Log:    toke.c,v $
  9.  * Revision 4.0.1.5  91/11/11  16:45:51  lwall
  10.  * patch19: default arg for shift was wrong after first subroutine definition
  11.  * 
  12.  * Revision 4.0.1.4  91/11/05  19:02:48  lwall
  13.  * patch11: \x and \c were subject to double interpretation in regexps
  14.  * patch11: prepared for ctype implementations that don't define isascii()
  15.  * patch11: nested list operators could miscount parens
  16.  * patch11: once-thru blocks didn't display right in the debugger
  17.  * patch11: sort eval "whatever" didn't work
  18.  * patch11: underscore is now allowed within literal octal and hex numbers
  19.  * 
  20.  * Revision 4.0.1.3  91/06/10  01:32:26  lwall
  21.  * patch10: m'$foo' now treats string as single quoted
  22.  * patch10: certain pattern optimizations were botched
  23.  * 
  24.  * Revision 4.0.1.2  91/06/07  12:05:56  lwall
  25.  * patch4: new copyright notice
  26.  * patch4: debugger lost track of lines in eval
  27.  * patch4: //o and s///o now optimize themselves fully at runtime
  28.  * patch4: added global modifier for pattern matches
  29.  * 
  30.  * Revision 4.0.1.1  91/04/12  09:18:18  lwall
  31.  * patch1: perl -de "print" wouldn't stop at the first statement
  32.  * 
  33.  * Revision 4.0  91/03/20  01:42:14  lwall
  34.  * 4.0 baseline.
  35.  * 
  36.  */
  37.  
  38. #include "EXTERN.h"
  39. #include "perl.h"
  40. #include "perly.h"
  41.  
  42. #ifdef I_FCNTL
  43. #include <fcntl.h>
  44. #endif
  45. #ifdef I_SYS_FILE
  46. #include <sys/file.h>
  47. #endif
  48.  
  49. #ifdef f_next
  50. #undef f_next
  51. #endif
  52.  
  53. /* which backslash sequences to keep in m// or s// */
  54.  
  55. static char *patleave = "\\.^$@dDwWsSbB+*?|()-nrtfeaxc0123456789[{]}";
  56.  
  57. char *reparse;        /* if non-null, scanident found ${foo[$bar]} */
  58.  
  59. void checkcomma();
  60.  
  61. #ifdef CLINE
  62. #undef CLINE
  63. #endif
  64. #define CLINE (cmdline = (curcmd->c_line < cmdline ? curcmd->c_line : cmdline))
  65.  
  66. #define META(c) ((c) | 128)
  67.  
  68. #define RETURN(retval) return (bufptr = s,(int)retval)
  69. #define OPERATOR(retval) return (expectterm = TRUE,bufptr = s,(int)retval)
  70. #define TERM(retval) return (CLINE, expectterm = FALSE,bufptr = s,(int)retval)
  71. #define LOOPX(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)LOOPEX)
  72. #define FTST(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)FILETEST)
  73. #define FUN0(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC0)
  74. #define FUN1(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC1)
  75. #define FUN2(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC2)
  76. #define FUN2x(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC2x)
  77. #define FUN3(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC3)
  78. #define FUN4(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC4)
  79. #define FUN5(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC5)
  80. #define FL(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FLIST)
  81. #define FL2(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FLIST2)
  82. #define HFUN(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)HSHFUN)
  83. #define HFUN3(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)HSHFUN3)
  84. #define LFUN(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LVALFUN)
  85. #define AOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)ADDOP)
  86. #define MOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)MULOP)
  87. #define EOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)EQOP)
  88. #define ROP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)RELOP)
  89. #define FOP(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP)
  90. #define FOP2(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP2)
  91. #define FOP3(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP3)
  92. #define FOP4(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP4)
  93. #define FOP22(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP22)
  94. #define FOP25(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP25)
  95.  
  96. /* This bit of chicanery makes a unary function followed by
  97.  * a parenthesis into a function with one argument, highest precedence.
  98.  */
  99. #define UNI(f) return(yylval.ival = f,expectterm = TRUE,bufptr = s, \
  100.     (*s == '(' || (s = skipspace(s), *s == '(') ? (int)FUNC1 : (int)UNIOP) )
  101.  
  102. /* This does similarly for list operators, merely by pretending that the
  103.  * paren came before the listop rather than after.
  104.  */
  105. #define LOP(f) return(CLINE, *s == '(' || (s = skipspace(s), *s == '(') ? \
  106.     (*s = (char) META('('), bufptr = oldbufptr, '(') : \
  107.     (yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP))
  108. /* grandfather return to old style */
  109. #define OLDLOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP)
  110.  
  111. char *
  112. skipspace(s)
  113. register char *s;
  114. {
  115.     while (s < bufend && isSPACE(*s))
  116.     s++;
  117.     return s;
  118. }
  119.  
  120. #ifdef CRIPPLED_CC
  121.  
  122. #undef UNI
  123. #undef LOP
  124. #define UNI(f) return uni(f,s)
  125. #define LOP(f) return lop(f,s)
  126.  
  127. int
  128. uni(f,s)
  129. int f;
  130. char *s;
  131. {
  132.     yylval.ival = f;
  133.     expectterm = TRUE;
  134.     bufptr = s;
  135.     if (*s == '(')
  136.     return FUNC1;
  137.     s = skipspace(s);
  138.     if (*s == '(')
  139.     return FUNC1;
  140.     else
  141.     return UNIOP;
  142. }
  143.  
  144. int
  145. lop(f,s)
  146. int f;
  147. char *s;
  148. {
  149.     CLINE;
  150.     if (*s != '(')
  151.     s = skipspace(s);
  152.     if (*s == '(') {
  153.     *s = META('(');
  154.     bufptr = oldbufptr;
  155.     return '(';
  156.     }
  157.     else {
  158.     yylval.ival=f;
  159.     expectterm = TRUE;
  160.     bufptr = s;
  161.     return LISTOP;
  162.     }
  163. }
  164.  
  165. #endif /* CRIPPLED_CC */
  166.  
  167. yylex()
  168. {
  169.     register char *s = bufptr;
  170.     register char *d;
  171.     register int tmp;
  172.     static bool in_format = FALSE;
  173.     static bool firstline = TRUE;
  174.     extern int yychar;        /* last token */
  175.  
  176.     oldoldbufptr = oldbufptr;
  177.     oldbufptr = s;
  178.  
  179.   retry:
  180. #ifdef YYDEBUG
  181.     if (debug & 1)
  182.     if (index(s,'\n'))
  183.         fprintf(stderr,"Tokener at %s",s);
  184.     else
  185.         fprintf(stderr,"Tokener at %s\n",s);
  186. #endif
  187. #ifdef macintosh
  188.      /* Ignore option-space */
  189.     if ((unsigned char) *s == 0312)
  190.          *s    =    ' ';
  191. #endif
  192. #ifdef BADSWITCH
  193.     if (*s & 128) {
  194.     if ((*s & 127) == '(') {
  195.         *s++ = '(';
  196.         oldbufptr = s;
  197.     }
  198.     else
  199.         warn("Unrecognized character \\%03o ignored", *s++ & 255);
  200.     goto retry;
  201.     }
  202. #endif
  203.     switch (*s) {
  204.     default:
  205.     if ((*s & 127) == '(') {
  206.         *s++ = '(';
  207.         oldbufptr = s;
  208.     }
  209.     else
  210.         warn("Unrecognized character \\%03o ignored", *s++ & 255);
  211.     goto retry;
  212.     case 4:
  213.     case 26:
  214.     goto fake_eof;            /* emulate EOF on ^D or ^Z */
  215.     case 0:
  216.     if (!rsfp)
  217.         RETURN(0);
  218.     if (s++ < bufend)
  219.         goto retry;            /* ignore stray nulls */
  220.     if (firstline) {
  221.         firstline = FALSE;
  222.         if (minus_n || minus_p || perldb) {
  223.         str_set(linestr,"");
  224.         if (perldb) {
  225.             char *getenv();
  226.             char *pdb = getenv("PERLDB");
  227.  
  228.             str_cat(linestr, pdb ? pdb : "require 'perldb.pl'");
  229.             str_cat(linestr, ";");
  230.         }
  231.         if (minus_n || minus_p) {
  232.             str_cat(linestr,"line: while (<>) {");
  233.             if (minus_l)
  234.             str_cat(linestr,"chop;");
  235.             if (minus_a)
  236.             str_cat(linestr,"@F=split(' ');");
  237.         }
  238.         oldoldbufptr = oldbufptr = s = str_get(linestr);
  239.         bufend = linestr->str_ptr + linestr->str_cur;
  240.         goto retry;
  241.         }
  242.     }
  243.     if (in_format) {
  244.         bufptr = bufend;
  245.         yylval.formval = load_format();
  246.         in_format = FALSE;
  247.         oldoldbufptr = oldbufptr = s = str_get(linestr) + 1;
  248.         bufend = linestr->str_ptr + linestr->str_cur;
  249.         OPERATOR(FORMLIST);
  250.     }
  251.     curcmd->c_line++;
  252. #ifdef CRYPTSCRIPT
  253.     cryptswitch();
  254. #endif /* CRYPTSCRIPT */
  255.     do {
  256.         if ((s = str_gets(linestr, rsfp, 0)) == Nullch) {
  257.           fake_eof:
  258.         if (rsfp) {
  259.             if (preprocess)
  260.             (void)mypclose(rsfp);
  261.             else if ((FILE*)rsfp == stdin)
  262.             clearerr(stdin);
  263.             else
  264.             (void)fclose(rsfp);
  265.             rsfp = Nullfp;
  266.         }
  267.         if (minus_n || minus_p) {
  268.             str_set(linestr,minus_p ? ";}continue{print" : "");
  269.             str_cat(linestr,";}");
  270.             oldoldbufptr = oldbufptr = s = str_get(linestr);
  271.             bufend = linestr->str_ptr + linestr->str_cur;
  272.             minus_n = minus_p = 0;
  273.             goto retry;
  274.         }
  275.         oldoldbufptr = oldbufptr = s = str_get(linestr);
  276.         str_set(linestr,"");
  277.         RETURN(';');    /* not infinite loop because rsfp is NULL now */
  278.         }
  279.         if (doextract && *linestr->str_ptr == '#')
  280.         doextract = FALSE;
  281.     } while (doextract);
  282.     oldoldbufptr = oldbufptr = bufptr = s;
  283.     if (perldb) {
  284.         STR *str = Str_new(85,0);
  285.  
  286.         str_sset(str,linestr);
  287.         astore(stab_xarray(curcmd->c_filestab),(int)curcmd->c_line,str);
  288.     }
  289. #ifdef DEBUG
  290.     if (firstline) {
  291.         char *showinput();
  292.         s = showinput();
  293.     }
  294. #endif
  295.     bufend = linestr->str_ptr + linestr->str_cur;
  296.     if (curcmd->c_line == 1) {
  297.         if (*s == '#' && s[1] == '!') {
  298.         if (!in_eval && !instr(s,"perl") && instr(origargv[0],"perl")) {
  299.             char **newargv;
  300.             char *cmd;
  301.  
  302.             s += 2;
  303.             if (*s == ' ')
  304.             s++;
  305.             cmd = s;
  306.             while (s < bufend && !isSPACE(*s))
  307.             s++;
  308.             *s++ = '\0';
  309.             while (s < bufend && isSPACE(*s))
  310.             s++;
  311.             if (s < bufend) {
  312.             Newz(899,newargv,origargc+3,char*);
  313.             newargv[1] = s;
  314.             while (s < bufend && !isSPACE(*s))
  315.                 s++;
  316.             *s = '\0';
  317.             Copy(origargv+1, newargv+2, origargc+1, char*);
  318.             }
  319.             else
  320.             newargv = origargv;
  321.             newargv[0] = cmd;
  322.             execv(cmd,newargv);
  323.             fatal("Can't exec %s", cmd);
  324.         }
  325.         }
  326.         else {
  327.         while (s < bufend && isSPACE(*s))
  328.             s++;
  329.         if (*s == ':')    /* for csh's that have to exec sh scripts */
  330.             s++;
  331.         }
  332.     }
  333.     goto retry;
  334.     case ' ': case '\t': case '\f': case '\r': case 013:
  335.     s++;
  336.     goto retry;
  337.     case '#':
  338.     if (preprocess && s == str_get(linestr) &&
  339.            s[1] == ' ' && (isDIGIT(s[2]) || strnEQ(s+2,"line ",5)) ) {
  340.         while (*s && !isDIGIT(*s))
  341.         s++;
  342.         curcmd->c_line = atoi(s)-1;
  343.         while (isDIGIT(*s))
  344.         s++;
  345.         d = bufend;
  346.         while (s < d && isSPACE(*s)) s++;
  347.         s[strlen(s)-1] = '\0';    /* wipe out newline */
  348.         if (*s == '"') {
  349.         s++;
  350.         s[strlen(s)-1] = '\0';    /* wipe out trailing quote */
  351.         }
  352.         if (*s)
  353.         curcmd->c_filestab = fstab(s);
  354.         else
  355.         curcmd->c_filestab = fstab(origfilename);
  356.         oldoldbufptr = oldbufptr = s = str_get(linestr);
  357.     }
  358.     /* FALL THROUGH */
  359.     case '\n':
  360.     if (in_eval && !rsfp) {
  361.         d = bufend;
  362.         while (s < d && *s != '\n')
  363.         s++;
  364.         if (s < d)
  365.         s++;
  366.         if (in_format) {
  367.         bufptr = s;
  368.         yylval.formval = load_format();
  369.         in_format = FALSE;
  370.         oldoldbufptr = oldbufptr = s = bufptr + 1;
  371.         TERM(FORMLIST);
  372.         }
  373.         curcmd->c_line++;
  374.     }
  375.     else {
  376.         *s = '\0';
  377.         bufend = s;
  378.     }
  379.     goto retry;
  380.     case '-':
  381.     if (s[1] && isALPHA(s[1]) && !isALPHA(s[2])) {
  382.         s++;
  383.         switch (*s++) {
  384.         case 'r': FTST(O_FTEREAD);
  385.         case 'w': FTST(O_FTEWRITE);
  386.         case 'x': FTST(O_FTEEXEC);
  387.         case 'o': FTST(O_FTEOWNED);
  388.         case 'R': FTST(O_FTRREAD);
  389.         case 'W': FTST(O_FTRWRITE);
  390.         case 'X': FTST(O_FTREXEC);
  391.         case 'O': FTST(O_FTROWNED);
  392.         case 'e': FTST(O_FTIS);
  393.         case 'z': FTST(O_FTZERO);
  394.         case 's': FTST(O_FTSIZE);
  395.         case 'f': FTST(O_FTFILE);
  396.         case 'd': FTST(O_FTDIR);
  397.         case 'l': FTST(O_FTLINK);
  398.         case 'p': FTST(O_FTPIPE);
  399.         case 'S': FTST(O_FTSOCK);
  400.         case 'u': FTST(O_FTSUID);
  401.         case 'g': FTST(O_FTSGID);
  402.         case 'k': FTST(O_FTSVTX);
  403.         case 'b': FTST(O_FTBLK);
  404.         case 'c': FTST(O_FTCHR);
  405.         case 't': FTST(O_FTTTY);
  406.         case 'T': FTST(O_FTTEXT);
  407.         case 'B': FTST(O_FTBINARY);
  408.         case 'M': stabent("\024",TRUE); FTST(O_FTMTIME);
  409.         case 'A': stabent("\024",TRUE); FTST(O_FTATIME);
  410.         case 'C': stabent("\024",TRUE); FTST(O_FTCTIME);
  411.         default:
  412.         s -= 2;
  413.         break;
  414.         }
  415.     }
  416.     tmp = *s++;
  417.     if (*s == tmp) {
  418.         s++;
  419.         RETURN(DEC);
  420.     }
  421.     if (expectterm)
  422.         OPERATOR('-');
  423.     else
  424.         AOP(O_SUBTRACT);
  425.     case '+':
  426.     tmp = *s++;
  427.     if (*s == tmp) {
  428.         s++;
  429.         RETURN(INC);
  430.     }
  431.     if (expectterm)
  432.         OPERATOR('+');
  433.     else
  434.         AOP(O_ADD);
  435.  
  436.     case '*':
  437.     if (expectterm) {
  438.         s = scanident(s,bufend,tokenbuf);
  439.         yylval.stabval = stabent(tokenbuf,TRUE);
  440.         TERM(STAR);
  441.     }
  442.     tmp = *s++;
  443.     if (*s == tmp) {
  444.         s++;
  445.         OPERATOR(POW);
  446.     }
  447.     MOP(O_MULTIPLY);
  448.     case '%':
  449.     if (expectterm) {
  450.         s = scanident(s,bufend,tokenbuf);
  451.         yylval.stabval = hadd(stabent(tokenbuf,TRUE));
  452.         TERM(HSH);
  453.     }
  454.     s++;
  455.     MOP(O_MODULO);
  456.  
  457.     case '^':
  458.     case '~':
  459.     case '(':
  460.     case ',':
  461.     case ':':
  462.     case '[':
  463.     tmp = *s++;
  464.     OPERATOR(tmp);
  465.     case '{':
  466.     tmp = *s++;
  467.     yylval.ival = curcmd->c_line;
  468.     if (isSPACE(*s) || *s == '#')
  469.         cmdline = NOLINE;   /* invalidate current command line number */
  470.     OPERATOR(tmp);
  471.     case ';':
  472.     if (curcmd->c_line < cmdline)
  473.         cmdline = curcmd->c_line;
  474.     tmp = *s++;
  475.     OPERATOR(tmp);
  476.     case ')':
  477.     case ']':
  478.     tmp = *s++;
  479.     TERM(tmp);
  480.     case '}':
  481.     tmp = *s++;
  482.     RETURN(tmp);
  483.     case '&':
  484.     s++;
  485.     tmp = *s++;
  486.     if (tmp == '&')
  487.         OPERATOR(ANDAND);
  488.     s--;
  489.     if (expectterm) {
  490.         d = bufend;
  491.         while (s < d && isSPACE(*s))
  492.         s++;
  493.         if (isALPHA(*s) || *s == '_' || *s == '\'')
  494.         *(--s) = '\\';    /* force next ident to WORD */
  495.         OPERATOR(AMPER);
  496.     }
  497.     OPERATOR('&');
  498.     case '|':
  499.     s++;
  500.     tmp = *s++;
  501.     if (tmp == '|')
  502.         OPERATOR(OROR);
  503.     s--;
  504.     OPERATOR('|');
  505.     case '=':
  506.     s++;
  507.     tmp = *s++;
  508.     if (tmp == '=')
  509.         EOP(O_EQ);
  510.     if (tmp == '~')
  511.         OPERATOR(MATCH);
  512.     s--;
  513.     OPERATOR('=');
  514.     case '!':
  515.     s++;
  516.     tmp = *s++;
  517.     if (tmp == '=')
  518.         EOP(O_NE);
  519.     if (tmp == '~')
  520.         OPERATOR(NMATCH);
  521.     s--;
  522.     OPERATOR('!');
  523.     case '<':
  524.     if (expectterm) {
  525.         s = scanstr(s);
  526.         TERM(RSTRING);
  527.     }
  528.     s++;
  529.     tmp = *s++;
  530.     if (tmp == '<')
  531.         OPERATOR(LS);
  532.     if (tmp == '=') {
  533.         tmp = *s++;
  534.         if (tmp == '>')
  535.         EOP(O_NCMP);
  536.         s--;
  537.         ROP(O_LE);
  538.     }
  539.     s--;
  540.     ROP(O_LT);
  541.     case '>':
  542.     s++;
  543.     tmp = *s++;
  544.     if (tmp == '>')
  545.         OPERATOR(RS);
  546.     if (tmp == '=')
  547.         ROP(O_GE);
  548.     s--;
  549.     ROP(O_GT);
  550.  
  551. #define SNARFWORD \
  552.     d = tokenbuf; \
  553.     while (isALNUM(*s) || *s == '\'') \
  554.         *d++ = *s++; \
  555.     while (d[-1] == '\'') \
  556.         d--,s--; \
  557.     *d = '\0'; \
  558.     d = tokenbuf;
  559.  
  560.     case '$':
  561.     if (s[1] == '#' && (isALPHA(s[2]) || s[2] == '_')) {
  562.         s++;
  563.         s = scanident(s,bufend,tokenbuf);
  564.         yylval.stabval = aadd(stabent(tokenbuf,TRUE));
  565.         TERM(ARYLEN);
  566.     }
  567.     d = s;
  568.     s = scanident(s,bufend,tokenbuf);
  569.     if (reparse) {        /* turn ${foo[bar]} into ($foo[bar]) */
  570.       do_reparse:
  571.         s[-1] = ')';
  572.         s = d;
  573.         s[1] = s[0];
  574.         s[0] = '(';
  575.         goto retry;
  576.     }
  577.     yylval.stabval = stabent(tokenbuf,TRUE);
  578.     TERM(REG);
  579.  
  580.     case '@':
  581.     d = s;
  582.     s = scanident(s,bufend,tokenbuf);
  583.     if (reparse)
  584.         goto do_reparse;
  585.     yylval.stabval = aadd(stabent(tokenbuf,TRUE));
  586.     TERM(ARY);
  587.  
  588.     case '/':            /* may either be division or pattern */
  589.     case '?':            /* may either be conditional or pattern */
  590.     if (expectterm) {
  591.         s = scanpat(s);
  592.         TERM(PATTERN);
  593.     }
  594.     tmp = *s++;
  595.     if (tmp == '/')
  596.         MOP(O_DIVIDE);
  597.     OPERATOR(tmp);
  598.  
  599.     case '.':
  600.     if (!expectterm || !isDIGIT(s[1])) {
  601.         tmp = *s++;
  602.         if (*s == tmp) {
  603.         s++;
  604.         OPERATOR(DOTDOT);
  605.         }
  606.         AOP(O_CONCAT);
  607.     }
  608.     /* FALL THROUGH */
  609.     case '0': case '1': case '2': case '3': case '4':
  610.     case '5': case '6': case '7': case '8': case '9':
  611.     case '\'': case '"': case '`':
  612.     s = scanstr(s);
  613.     TERM(RSTRING);
  614.  
  615.     case '\\':    /* some magic to force next word to be a WORD */
  616.     s++;    /* used by do and sub to force a separate namespace */
  617.     /* FALL THROUGH */
  618.     case '_':
  619.     SNARFWORD;
  620.     if (d[1] == '_') {
  621.         if (strEQ(d,"__LINE__") || strEQ(d,"__FILE__")) {
  622.         ARG *arg = op_new(1);
  623.  
  624.         yylval.arg = arg;
  625.         arg->arg_type = O_ITEM;
  626.         if (d[2] == 'L')
  627.             (void)sprintf(tokenbuf,"%ld",(long)curcmd->c_line);
  628.         else
  629.             strcpy(tokenbuf, stab_val(curcmd->c_filestab)->str_ptr);
  630.         arg[1].arg_type = A_SINGLE;
  631.         arg[1].arg_ptr.arg_str = str_make(tokenbuf,strlen(tokenbuf));
  632.         TERM(RSTRING);
  633.         }
  634.         else if (strEQ(d,"__END__")) {
  635. #ifndef TAINT
  636.         STAB *stab;
  637.         int fd;
  638.  
  639.         /*SUPPRESS 560*/
  640.         if (stab = stabent("DATA",FALSE)) {
  641.             stab->str_pok |= SP_MULTI;
  642.             stab_io(stab) = stio_new();
  643.             stab_io(stab)->ifp = rsfp;
  644. #if defined(HAS_FCNTL) && defined(F_SETFD)
  645.             fd = fileno(rsfp);
  646.             fcntl(fd,F_SETFD,fd >= 3);
  647. #endif
  648.             if (preprocess)
  649.             stab_io(stab)->type = '|';
  650.             else if ((FILE*)rsfp == stdin)
  651.             stab_io(stab)->type = '-';
  652.             else
  653.             stab_io(stab)->type = '<';
  654.             rsfp = Nullfp;
  655.         }
  656. #endif
  657.         goto fake_eof;
  658.         }
  659.     }
  660.     break;
  661.     case 'a': case 'A':
  662.     SNARFWORD;
  663.     if (strEQ(d,"alarm"))
  664.         UNI(O_ALARM);
  665.     if (strEQ(d,"accept"))
  666.         FOP22(O_ACCEPT);
  667.     if (strEQ(d,"atan2"))
  668.         FUN2(O_ATAN2);
  669.     break;
  670.     case 'b': case 'B':
  671.     SNARFWORD;
  672.     if (strEQ(d,"bind"))
  673.         FOP2(O_BIND);
  674.     if (strEQ(d,"binmode"))
  675.         FOP(O_BINMODE);
  676.     break;
  677.     case 'c': case 'C':
  678.     SNARFWORD;
  679.     if (strEQ(d,"chop"))
  680.         LFUN(O_CHOP);
  681.     if (strEQ(d,"continue"))
  682.         OPERATOR(CONTINUE);
  683.     if (strEQ(d,"chdir")) {
  684.         (void)stabent("ENV",TRUE);    /* may use HOME */
  685.         UNI(O_CHDIR);
  686.     }
  687.     if (strEQ(d,"close"))
  688.         FOP(O_CLOSE);
  689.     if (strEQ(d,"closedir"))
  690.         FOP(O_CLOSEDIR);
  691.     if (strEQ(d,"cmp"))
  692.         EOP(O_SCMP);
  693.     if (strEQ(d,"caller"))
  694.         UNI(O_CALLER);
  695.     if (strEQ(d,"crypt")) {
  696. #ifdef FCRYPT
  697.         static int cryptseen = 0;
  698.  
  699.         if (!cryptseen++)
  700.         init_des();
  701. #endif
  702.         FUN2(O_CRYPT);
  703.     }
  704.     if (strEQ(d,"chmod"))
  705.         LOP(O_CHMOD);
  706.     if (strEQ(d,"chown"))
  707.         LOP(O_CHOWN);
  708.     if (strEQ(d,"connect"))
  709.         FOP2(O_CONNECT);
  710.     if (strEQ(d,"cos"))
  711.         UNI(O_COS);
  712.     if (strEQ(d,"chroot"))
  713.         UNI(O_CHROOT);
  714.     break;
  715.     case 'd': case 'D':
  716.     SNARFWORD;
  717.     if (strEQ(d,"do")) {
  718.         d = bufend;
  719.         while (s < d && isSPACE(*s))
  720.         s++;
  721.         if (isALPHA(*s) || *s == '_')
  722.         *(--s) = '\\';    /* force next ident to WORD */
  723.         OPERATOR(DO);
  724.     }
  725.     if (strEQ(d,"die"))
  726.         LOP(O_DIE);
  727.     if (strEQ(d,"defined"))
  728.         LFUN(O_DEFINED);
  729.     if (strEQ(d,"delete"))
  730.         OPERATOR(DELETE);
  731.     if (strEQ(d,"dbmopen"))
  732.         HFUN3(O_DBMOPEN);
  733.     if (strEQ(d,"dbmclose"))
  734.         HFUN(O_DBMCLOSE);
  735.     if (strEQ(d,"dump"))
  736.         LOOPX(O_DUMP);
  737.     break;
  738.     case 'e': case 'E':
  739.     SNARFWORD;
  740.     if (strEQ(d,"else"))
  741.         OPERATOR(ELSE);
  742.     if (strEQ(d,"elsif")) {
  743.         yylval.ival = curcmd->c_line;
  744.         OPERATOR(ELSIF);
  745.     }
  746.     if (strEQ(d,"eq") || strEQ(d,"EQ"))
  747.         EOP(O_SEQ);
  748.     if (strEQ(d,"exit"))
  749.         UNI(O_EXIT);
  750.     if (strEQ(d,"eval")) {
  751.         allstabs = TRUE;        /* must initialize everything since */
  752.         UNI(O_EVAL);        /* we don't know what will be used */
  753.     }
  754.     if (strEQ(d,"eof"))
  755.         FOP(O_EOF);
  756.     if (strEQ(d,"exp"))
  757.         UNI(O_EXP);
  758.     if (strEQ(d,"each"))
  759.         HFUN(O_EACH);
  760.     if (strEQ(d,"exec")) {
  761.         set_csh();
  762.         LOP(O_EXEC_OP);
  763.     }
  764.     if (strEQ(d,"endhostent"))
  765.         FUN0(O_EHOSTENT);
  766.     if (strEQ(d,"endnetent"))
  767.         FUN0(O_ENETENT);
  768.     if (strEQ(d,"endservent"))
  769.         FUN0(O_ESERVENT);
  770.     if (strEQ(d,"endprotoent"))
  771.         FUN0(O_EPROTOENT);
  772.     if (strEQ(d,"endpwent"))
  773.         FUN0(O_EPWENT);
  774.     if (strEQ(d,"endgrent"))
  775.         FUN0(O_EGRENT);
  776.     break;
  777.     case 'f': case 'F':
  778.     SNARFWORD;
  779.     if (strEQ(d,"for") || strEQ(d,"foreach")) {
  780.         yylval.ival = curcmd->c_line;
  781.         OPERATOR(FOR);
  782.     }
  783.     if (strEQ(d,"format")) {
  784.         d = bufend;
  785.         while (s < d && isSPACE(*s))
  786.         s++;
  787.         if (isALPHA(*s) || *s == '_')
  788.         *(--s) = '\\';    /* force next ident to WORD */
  789.         in_format = TRUE;
  790.         allstabs = TRUE;        /* must initialize everything since */
  791.         OPERATOR(FORMAT);        /* we don't know what will be used */
  792.     }
  793.     if (strEQ(d,"fork"))
  794.         FUN0(O_FORK);
  795.     if (strEQ(d,"fcntl"))
  796.         FOP3(O_FCNTL);
  797.     if (strEQ(d,"fileno"))
  798.         FOP(O_FILENO);
  799.     if (strEQ(d,"flock"))
  800.         FOP2(O_FLOCK);
  801.     break;
  802.     case 'g': case 'G':
  803.     SNARFWORD;
  804.     if (strEQ(d,"gt") || strEQ(d,"GT"))
  805.         ROP(O_SGT);
  806.     if (strEQ(d,"ge") || strEQ(d,"GE"))
  807.         ROP(O_SGE);
  808.     if (strEQ(d,"grep"))
  809.         FL2(O_GREP);
  810.     if (strEQ(d,"goto"))
  811.         LOOPX(O_GOTO);
  812.     if (strEQ(d,"gmtime"))
  813.         UNI(O_GMTIME);
  814.     if (strEQ(d,"getc"))
  815.         FOP(O_GETC);
  816.     if (strnEQ(d,"get",3)) {
  817.         d += 3;
  818.         if (*d == 'p') {
  819.         if (strEQ(d,"ppid"))
  820.             FUN0(O_GETPPID);
  821.         if (strEQ(d,"pgrp"))
  822.             UNI(O_GETPGRP);
  823.         if (strEQ(d,"priority"))
  824.             FUN2(O_GETPRIORITY);
  825.         if (strEQ(d,"protobyname"))
  826.             UNI(O_GPBYNAME);
  827.         if (strEQ(d,"protobynumber"))
  828.             FUN1(O_GPBYNUMBER);
  829.         if (strEQ(d,"protoent"))
  830.             FUN0(O_GPROTOENT);
  831.         if (strEQ(d,"pwent"))
  832.             FUN0(O_GPWENT);
  833.         if (strEQ(d,"pwnam"))
  834.             FUN1(O_GPWNAM);
  835.         if (strEQ(d,"pwuid"))
  836.             FUN1(O_GPWUID);
  837.         if (strEQ(d,"peername"))
  838.             FOP(O_GETPEERNAME);
  839.         }
  840.         else if (*d == 'h') {
  841.         if (strEQ(d,"hostbyname"))
  842.             UNI(O_GHBYNAME);
  843.         if (strEQ(d,"hostbyaddr"))
  844.             FUN2(O_GHBYADDR);
  845.         if (strEQ(d,"hostent"))
  846.             FUN0(O_GHOSTENT);
  847.         }
  848.         else if (*d == 'n') {
  849.         if (strEQ(d,"netbyname"))
  850.             UNI(O_GNBYNAME);
  851.         if (strEQ(d,"netbyaddr"))
  852.             FUN2(O_GNBYADDR);
  853.         if (strEQ(d,"netent"))
  854.             FUN0(O_GNETENT);
  855.         }
  856.         else if (*d == 's') {
  857.         if (strEQ(d,"servbyname"))
  858.             FUN2(O_GSBYNAME);
  859.         if (strEQ(d,"servbyport"))
  860.             FUN2(O_GSBYPORT);
  861.         if (strEQ(d,"servent"))
  862.             FUN0(O_GSERVENT);
  863.         if (strEQ(d,"sockname"))
  864.             FOP(O_GETSOCKNAME);
  865.         if (strEQ(d,"sockopt"))
  866.             FOP3(O_GSOCKOPT);
  867.         }
  868.         else if (*d == 'g') {
  869.         if (strEQ(d,"grent"))
  870.             FUN0(O_GGRENT);
  871.         if (strEQ(d,"grnam"))
  872.             FUN1(O_GGRNAM);
  873.         if (strEQ(d,"grgid"))
  874.             FUN1(O_GGRGID);
  875.         }
  876.         else if (*d == 'l') {
  877.         if (strEQ(d,"login"))
  878.             FUN0(O_GETLOGIN);
  879.         }
  880.         d -= 3;
  881.     }
  882.     break;
  883.     case 'h': case 'H':
  884.     SNARFWORD;
  885.     if (strEQ(d,"hex"))
  886.         UNI(O_HEX);
  887.     break;
  888.     case 'i': case 'I':
  889.     SNARFWORD;
  890.     if (strEQ(d,"if")) {
  891.         yylval.ival = curcmd->c_line;
  892.         OPERATOR(IF);
  893.     }
  894.     if (strEQ(d,"index"))
  895.         FUN2x(O_INDEX);
  896.     if (strEQ(d,"int"))
  897.         UNI(O_INT);
  898.     if (strEQ(d,"ioctl"))
  899.         FOP3(O_IOCTL);
  900.     break;
  901.     case 'j': case 'J':
  902.     SNARFWORD;
  903.     if (strEQ(d,"join"))
  904.         FL2(O_JOIN);
  905.     break;
  906.     case 'k': case 'K':
  907.     SNARFWORD;
  908.     if (strEQ(d,"keys"))
  909.         HFUN(O_KEYS);
  910.     if (strEQ(d,"kill"))
  911.         LOP(O_KILL);
  912.     break;
  913.     case 'l': case 'L':
  914.     SNARFWORD;
  915.     if (strEQ(d,"last"))
  916.         LOOPX(O_LAST);
  917.     if (strEQ(d,"local"))
  918.         OPERATOR(LOCAL);
  919.     if (strEQ(d,"length"))
  920.         UNI(O_LENGTH);
  921.     if (strEQ(d,"lt") || strEQ(d,"LT"))
  922.         ROP(O_SLT);
  923.     if (strEQ(d,"le") || strEQ(d,"LE"))
  924.         ROP(O_SLE);
  925.     if (strEQ(d,"localtime"))
  926.         UNI(O_LOCALTIME);
  927.     if (strEQ(d,"log"))
  928.         UNI(O_LOG);
  929.     if (strEQ(d,"link"))
  930.         FUN2(O_LINK);
  931.     if (strEQ(d,"listen"))
  932.         FOP2(O_LISTEN);
  933.     if (strEQ(d,"lstat"))
  934.         FOP(O_LSTAT);
  935.     break;
  936.     case 'm': case 'M':
  937.     if (s[1] == '\'') {
  938.         d = "m";
  939.         s++;
  940.     }
  941.     else {
  942.         SNARFWORD;
  943.     }
  944.     if (strEQ(d,"m")) {
  945.         s = scanpat(s-1);
  946.         if (yylval.arg)
  947.         TERM(PATTERN);
  948.         else
  949.         RETURN(1);    /* force error */
  950.     }
  951.     switch (d[1]) {
  952.     case 'k':
  953.         if (strEQ(d,"mkdir"))
  954.         FUN2(O_MKDIR);
  955.         break;
  956.     case 's':
  957.         if (strEQ(d,"msgctl"))
  958.         FUN3(O_MSGCTL);
  959.         if (strEQ(d,"msgget"))
  960.         FUN2(O_MSGGET);
  961.         if (strEQ(d,"msgrcv"))
  962.         FUN5(O_MSGRCV);
  963.         if (strEQ(d,"msgsnd"))
  964.         FUN3(O_MSGSND);
  965.         break;
  966.     }
  967.     break;
  968.     case 'n': case 'N':
  969.     SNARFWORD;
  970.     if (strEQ(d,"next"))
  971.         LOOPX(O_NEXT);
  972.     if (strEQ(d,"ne") || strEQ(d,"NE"))
  973.         EOP(O_SNE);
  974.     break;
  975.     case 'o': case 'O':
  976.     SNARFWORD;
  977.     if (strEQ(d,"open"))
  978.         OPERATOR(OPEN);
  979.     if (strEQ(d,"ord"))
  980.         UNI(O_ORD);
  981.     if (strEQ(d,"oct"))
  982.         UNI(O_OCT);
  983.     if (strEQ(d,"opendir"))
  984.         FOP2(O_OPEN_DIR);
  985.     break;
  986.     case 'p': case 'P':
  987.     SNARFWORD;
  988.     if (strEQ(d,"print")) {
  989.         checkcomma(s,"filehandle");
  990.         LOP(O_PRINT);
  991.     }
  992.     if (strEQ(d,"printf")) {
  993.         checkcomma(s,"filehandle");
  994.         LOP(O_PRTF);
  995.     }
  996.     if (strEQ(d,"push")) {
  997.         yylval.ival = O_PUSH;
  998.         OPERATOR(PUSH);
  999.     }
  1000.     if (strEQ(d,"pop"))
  1001.         OPERATOR(POP);
  1002.     if (strEQ(d,"pack"))
  1003.         FL2(O_PACK);
  1004.     if (strEQ(d,"package"))
  1005.         OPERATOR(PACKAGE);
  1006.     if (strEQ(d,"pipe"))
  1007.         FOP22(O_PIPE);
  1008.     break;
  1009.     case 'q': case 'Q':
  1010.     SNARFWORD;
  1011.     if (strEQ(d,"q")) {
  1012.         s = scanstr(s-1);
  1013.         TERM(RSTRING);
  1014.     }
  1015.     if (strEQ(d,"qq")) {
  1016.         s = scanstr(s-2);
  1017.         TERM(RSTRING);
  1018.     }
  1019.     if (strEQ(d,"qx")) {
  1020.         s = scanstr(s-2);
  1021.         TERM(RSTRING);
  1022.     }
  1023.     break;
  1024.     case 'r': case 'R':
  1025.     SNARFWORD;
  1026.     if (strEQ(d,"return"))
  1027.         OLDLOP(O_RETURN);
  1028.     if (strEQ(d,"require")) {
  1029.         allstabs = TRUE;        /* must initialize everything since */
  1030.         UNI(O_REQUIRE);        /* we don't know what will be used */
  1031.     }
  1032.     if (strEQ(d,"reset"))
  1033.         UNI(O_RESET);
  1034.     if (strEQ(d,"redo"))
  1035.         LOOPX(O_REDO);
  1036.     if (strEQ(d,"rename"))
  1037.         FUN2(O_RENAME);
  1038.     if (strEQ(d,"rand"))
  1039.         UNI(O_RAND);
  1040.     if (strEQ(d,"rmdir"))
  1041.         UNI(O_RMDIR);
  1042.     if (strEQ(d,"rindex"))
  1043.         FUN2x(O_RINDEX);
  1044.     if (strEQ(d,"read"))
  1045.         FOP3(O_READ);
  1046.     if (strEQ(d,"readdir"))
  1047.         FOP(O_READDIR);
  1048.     if (strEQ(d,"rewinddir"))
  1049.         FOP(O_REWINDDIR);
  1050.     if (strEQ(d,"recv"))
  1051.         FOP4(O_RECV);
  1052.     if (strEQ(d,"reverse"))
  1053.         LOP(O_REVERSE);
  1054.     if (strEQ(d,"readlink"))
  1055.         UNI(O_READLINK);
  1056.     break;
  1057.     case 's': case 'S':
  1058.     if (s[1] == '\'') {
  1059.         d = "s";
  1060.         s++;
  1061.     }
  1062.     else {
  1063.         SNARFWORD;
  1064.     }
  1065.     if (strEQ(d,"s")) {
  1066.         s = scansubst(s);
  1067.         if (yylval.arg)
  1068.         TERM(SUBST);
  1069.         else
  1070.         RETURN(1);    /* force error */
  1071.     }
  1072.     switch (d[1]) {
  1073.     case 'a':
  1074.     case 'b':
  1075.         break;
  1076.     case 'c':
  1077.         if (strEQ(d,"scalar"))
  1078.         UNI(O_SCALAR);
  1079.         break;
  1080.     case 'd':
  1081.         break;
  1082.     case 'e':
  1083.         if (strEQ(d,"select"))
  1084.         OPERATOR(SSELECT);
  1085.         if (strEQ(d,"seek"))
  1086.         FOP3(O_SEEK);
  1087.         if (strEQ(d,"semctl"))
  1088.         FUN4(O_SEMCTL);
  1089.         if (strEQ(d,"semget"))
  1090.         FUN3(O_SEMGET);
  1091.         if (strEQ(d,"semop"))
  1092.         FUN2(O_SEMOP);
  1093.         if (strEQ(d,"send"))
  1094.         FOP3(O_SEND);
  1095.         if (strEQ(d,"setpgrp"))
  1096.         FUN2(O_SETPGRP);
  1097.         if (strEQ(d,"setpriority"))
  1098.         FUN3(O_SETPRIORITY);
  1099.         if (strEQ(d,"sethostent"))
  1100.         FUN1(O_SHOSTENT);
  1101.         if (strEQ(d,"setnetent"))
  1102.         FUN1(O_SNETENT);
  1103.         if (strEQ(d,"setservent"))
  1104.         FUN1(O_SSERVENT);
  1105.         if (strEQ(d,"setprotoent"))
  1106.         FUN1(O_SPROTOENT);
  1107.         if (strEQ(d,"setpwent"))
  1108.         FUN0(O_SPWENT);
  1109.         if (strEQ(d,"setgrent"))
  1110.         FUN0(O_SGRENT);
  1111.         if (strEQ(d,"seekdir"))
  1112.         FOP2(O_SEEKDIR);
  1113.         if (strEQ(d,"setsockopt"))
  1114.         FOP4(O_SSOCKOPT);
  1115.         break;
  1116.     case 'f':
  1117.     case 'g':
  1118.         break;
  1119.     case 'h':
  1120.         if (strEQ(d,"shift"))
  1121.         TERM(SHIFT);
  1122.         if (strEQ(d,"shmctl"))
  1123.         FUN3(O_SHMCTL);
  1124.         if (strEQ(d,"shmget"))
  1125.         FUN3(O_SHMGET);
  1126.         if (strEQ(d,"shmread"))
  1127.         FUN4(O_SHMREAD);
  1128.         if (strEQ(d,"shmwrite"))
  1129.         FUN4(O_SHMWRITE);
  1130.         if (strEQ(d,"shutdown"))
  1131.         FOP2(O_SHUTDOWN);
  1132.         break;
  1133.     case 'i':
  1134.         if (strEQ(d,"sin"))
  1135.         UNI(O_SIN);
  1136.         break;
  1137.     case 'j':
  1138.     case 'k':
  1139.         break;
  1140.     case 'l':
  1141.         if (strEQ(d,"sleep"))
  1142.         UNI(O_SLEEP);
  1143.         break;
  1144.     case 'm':
  1145.     case 'n':
  1146.         break;
  1147.     case 'o':
  1148.         if (strEQ(d,"socket"))
  1149.         FOP4(O_SOCKET);
  1150.         if (strEQ(d,"socketpair"))
  1151.         FOP25(O_SOCKPAIR);
  1152.         if (strEQ(d,"sort")) {
  1153.         checkcomma(s,"subroutine name");
  1154.         d = bufend;
  1155.         while (s < d && isSPACE(*s)) s++;
  1156.         if (*s == ';' || *s == ')')        /* probably a close */
  1157.             fatal("sort is now a reserved word");
  1158.         if (isALPHA(*s) || *s == '_') {
  1159.             /*SUPPRESS 530*/
  1160.             for (d = s; isALNUM(*d); d++) ;
  1161.             strncpy(tokenbuf,s,d-s);
  1162.             if (strNE(tokenbuf,"keys") &&
  1163.             strNE(tokenbuf,"values") &&
  1164.             strNE(tokenbuf,"split") &&
  1165.             strNE(tokenbuf,"grep") &&
  1166.             strNE(tokenbuf,"readdir") &&
  1167.             strNE(tokenbuf,"unpack") &&
  1168.             strNE(tokenbuf,"do") &&
  1169.             strNE(tokenbuf,"eval") &&
  1170.             (d >= bufend || isSPACE(*d)) )
  1171.             *(--s) = '\\';    /* force next ident to WORD */
  1172.         }
  1173.         LOP(O_SORT);
  1174.         }
  1175.         break;
  1176.     case 'p':
  1177.         if (strEQ(d,"split"))
  1178.         TERM(SPLIT);
  1179.         if (strEQ(d,"sprintf"))
  1180.         FL(O_SPRINTF);
  1181.         if (strEQ(d,"splice")) {
  1182.         yylval.ival = O_SPLICE;
  1183.         OPERATOR(PUSH);
  1184.         }
  1185.         break;
  1186.     case 'q':
  1187.         if (strEQ(d,"sqrt"))
  1188.         UNI(O_SQRT);
  1189.         break;
  1190.     case 'r':
  1191.         if (strEQ(d,"srand"))
  1192.         UNI(O_SRAND);
  1193.         break;
  1194.     case 's':
  1195.         break;
  1196.     case 't':
  1197.         if (strEQ(d,"stat"))
  1198.         FOP(O_STAT);
  1199.         if (strEQ(d,"study")) {
  1200.         sawstudy++;
  1201.         LFUN(O_STUDY);
  1202.         }
  1203.         break;
  1204.     case 'u':
  1205.         if (strEQ(d,"substr"))
  1206.         FUN2x(O_SUBSTR);
  1207.         if (strEQ(d,"sub")) {
  1208.         yylval.ival = savestack->ary_fill; /* restore stuff on reduce */
  1209.         savelong(&subline);
  1210.         saveitem(subname);
  1211.  
  1212.         subline = curcmd->c_line;
  1213.         d = bufend;
  1214.         while (s < d && isSPACE(*s))
  1215.             s++;
  1216.         if (isALPHA(*s) || *s == '_' || *s == '\'') {
  1217.             str_sset(subname,curstname);
  1218.             str_ncat(subname,"'",1);
  1219.             for (d = s+1; isALNUM(*d) || *d == '\''; d++)
  1220.             /*SUPPRESS 530*/
  1221.             ;
  1222.             if (d[-1] == '\'')
  1223.             d--;
  1224.             str_ncat(subname,s,d-s);
  1225.             *(--s) = '\\';    /* force next ident to WORD */
  1226.         }
  1227.         else
  1228.             str_set(subname,"?");
  1229.         OPERATOR(SUB);
  1230.         }
  1231.         break;
  1232.     case 'v':
  1233.     case 'w':
  1234.     case 'x':
  1235.         break;
  1236.     case 'y':
  1237.         if (strEQ(d,"system")) {
  1238.         set_csh();
  1239.         LOP(O_SYSTEM);
  1240.         }
  1241.         if (strEQ(d,"symlink"))
  1242.         FUN2(O_SYMLINK);
  1243.         if (strEQ(d,"syscall"))
  1244.         LOP(O_SYSCALL);
  1245.         if (strEQ(d,"sysread"))
  1246.         FOP3(O_SYSREAD);
  1247.         if (strEQ(d,"syswrite"))
  1248.         FOP3(O_SYSWRITE);
  1249.         break;
  1250.     case 'z':
  1251.         break;
  1252.     }
  1253.     break;
  1254.     case 't': case 'T':
  1255.     SNARFWORD;
  1256.     if (strEQ(d,"tr")) {
  1257.         s = scantrans(s);
  1258.         if (yylval.arg)
  1259.         TERM(TRANS);
  1260.         else
  1261.         RETURN(1);    /* force error */
  1262.     }
  1263.     if (strEQ(d,"tell"))
  1264.         FOP(O_TELL);
  1265.     if (strEQ(d,"telldir"))
  1266.         FOP(O_TELLDIR);
  1267.     if (strEQ(d,"time"))
  1268.         FUN0(O_TIME);
  1269.     if (strEQ(d,"times"))
  1270.         FUN0(O_TMS);
  1271.     if (strEQ(d,"truncate"))
  1272.         FOP2(O_TRUNCATE);
  1273.     break;
  1274.     case 'u': case 'U':
  1275.     SNARFWORD;
  1276.     if (strEQ(d,"using"))
  1277.         OPERATOR(USING);
  1278.     if (strEQ(d,"until")) {
  1279.         yylval.ival = curcmd->c_line;
  1280.         OPERATOR(UNTIL);
  1281.     }
  1282.     if (strEQ(d,"unless")) {
  1283.         yylval.ival = curcmd->c_line;
  1284.         OPERATOR(UNLESS);
  1285.     }
  1286.     if (strEQ(d,"unlink"))
  1287.         LOP(O_UNLINK);
  1288.     if (strEQ(d,"undef"))
  1289.         LFUN(O_UNDEF);
  1290.     if (strEQ(d,"unpack"))
  1291.         FUN2(O_UNPACK);
  1292.     if (strEQ(d,"utime"))
  1293.         LOP(O_UTIME);
  1294.     if (strEQ(d,"umask"))
  1295.         UNI(O_UMASK);
  1296.     if (strEQ(d,"unshift")) {
  1297.         yylval.ival = O_UNSHIFT;
  1298.         OPERATOR(PUSH);
  1299.     }
  1300.     break;
  1301.     case 'v': case 'V':
  1302.     SNARFWORD;
  1303.     if (strEQ(d,"values"))
  1304.         HFUN(O_VALUES);
  1305.     if (strEQ(d,"vec")) {
  1306.         sawvec = TRUE;
  1307.         FUN3(O_VEC);
  1308.     }
  1309.     break;
  1310.     case 'w': case 'W':
  1311.     SNARFWORD;
  1312.     if (strEQ(d,"while")) {
  1313.         yylval.ival = curcmd->c_line;
  1314.         OPERATOR(WHILE);
  1315.     }
  1316.     if (strEQ(d,"warn"))
  1317.         LOP(O_WARN);
  1318.     if (strEQ(d,"wait"))
  1319.         FUN0(O_WAIT);
  1320.     if (strEQ(d,"waitpid"))
  1321.         FUN2(O_WAITPID);
  1322.     if (strEQ(d,"wantarray")) {
  1323.         yylval.arg = op_new(1);
  1324.         yylval.arg->arg_type = O_ITEM;
  1325.         yylval.arg[1].arg_type = A_WANTARRAY;
  1326.         TERM(RSTRING);
  1327.     }
  1328.     if (strEQ(d,"write"))
  1329.         FOP(O_WRITE);
  1330.     break;
  1331.     case 'x': case 'X':
  1332.     SNARFWORD;
  1333.     if (!expectterm && strEQ(d,"x"))
  1334.         MOP(O_REPEAT);
  1335.     break;
  1336.     case 'y': case 'Y':
  1337.     if (s[1] == '\'') {
  1338.         d = "y";
  1339.         s++;
  1340.     }
  1341.     else {
  1342.         SNARFWORD;
  1343.     }
  1344.     if (strEQ(d,"y")) {
  1345.         s = scantrans(s);
  1346.         TERM(TRANS);
  1347.     }
  1348.     break;
  1349.     case 'z': case 'Z':
  1350.     SNARFWORD;
  1351.     break;
  1352.     }
  1353.     yylval.cval = savestr(d);
  1354.     expectterm = FALSE;
  1355.     if (oldoldbufptr && oldoldbufptr < bufptr) {
  1356.     while (isSPACE(*oldoldbufptr))
  1357.         oldoldbufptr++;
  1358.     if (*oldoldbufptr == 'p' && strnEQ(oldoldbufptr,"print",5))
  1359.         expectterm = TRUE;
  1360.     else if (*oldoldbufptr == 's' && strnEQ(oldoldbufptr,"sort",4))
  1361.         expectterm = TRUE;
  1362.     }
  1363.     return (CLINE, bufptr = s, (int)WORD);
  1364. }
  1365.  
  1366. void
  1367. checkcomma(s,what)
  1368. register char *s;
  1369. char *what;
  1370. {
  1371.     char *someword;
  1372.  
  1373.     if (*s == '(')
  1374.     s++;
  1375.     while (s < bufend && isSPACE(*s))
  1376.     s++;
  1377.     if (isALPHA(*s) || *s == '_') {
  1378.     someword = s++;
  1379.     while (isALNUM(*s))
  1380.         s++;
  1381.     while (s < bufend && isSPACE(*s))
  1382.         s++;
  1383.     if (*s == ',') {
  1384.         *s = '\0';
  1385.         someword = instr(
  1386.           "tell eof times getlogin wait length shift umask getppid \
  1387.           cos exp int log rand sin sqrt ord wantarray",
  1388.           someword);
  1389.         *s = ',';
  1390.         if (someword)
  1391.         return;
  1392.         fatal("No comma allowed after %s", what);
  1393.     }
  1394.     }
  1395. }
  1396.  
  1397. char *
  1398. scanident(s,send,dest)
  1399. register char *s;
  1400. register char *send;
  1401. char *dest;
  1402. {
  1403.     register char *d;
  1404.     int brackets = 0;
  1405.  
  1406.     reparse = Nullch;
  1407.     s++;
  1408.     d = dest;
  1409.     if (isDIGIT(*s)) {
  1410.     while (isDIGIT(*s))
  1411.         *d++ = *s++;
  1412.     }
  1413.     else {
  1414.     while (isALNUM(*s) || *s == '\'')
  1415.         *d++ = *s++;
  1416.     }
  1417.     while (d > dest+1 && d[-1] == '\'')
  1418.     d--,s--;
  1419.     *d = '\0';
  1420.     d = dest;
  1421.     if (!*d) {
  1422.     *d = *s++;
  1423.     if (*d == '{' /* } */ ) {
  1424.         d = dest;
  1425.         brackets++;
  1426.         while (s < send && brackets) {
  1427.         if (!reparse && (d == dest || (*s && isALNUM(*s) ))) {
  1428.             *d++ = *s++;
  1429.             continue;
  1430.         }
  1431.         else if (!reparse)
  1432.             reparse = s;
  1433.         switch (*s++) {
  1434.         /* { */
  1435.         case '}':
  1436.             brackets--;
  1437.             if (reparse && reparse == s - 1)
  1438.             reparse = Nullch;
  1439.             break;
  1440.         case '{':   /* } */
  1441.             brackets++;
  1442.             break;
  1443.         }
  1444.         }
  1445.         *d = '\0';
  1446.         d = dest;
  1447.     }
  1448.     else
  1449.         d[1] = '\0';
  1450.     }
  1451.     if (*d == '^' && (isUPPER(*s) || index("[\\]^_?", *s))) {
  1452. #ifdef DEBUGGING
  1453.     if (*s == 'D')
  1454.         debug |= 32768;
  1455. #endif
  1456.     *d = *s++ ^ 64;
  1457.     }
  1458.     return s;
  1459. }
  1460.  
  1461. void
  1462. scanconst(spat,string,len)
  1463. SPAT *spat;
  1464. char *string;
  1465. int len;
  1466. {
  1467.     register STR *tmpstr;
  1468.     register char *t;
  1469.     register char *d;
  1470.     register char *e;
  1471.     char *origstring = string;
  1472.     static char *vert = "|";
  1473.  
  1474.     if (ninstr(string, string+len, vert, vert+1))
  1475.     return;
  1476.     if (*string == '^')
  1477.     string++, len--;
  1478.     tmpstr = Str_new(86,len);
  1479.     str_nset(tmpstr,string,len);
  1480.     t = str_get(tmpstr);
  1481.     e = t + len;
  1482.     tmpstr->str_u.str_useful = 100;
  1483.     for (d=t; d < e; ) {
  1484.     switch (*d) {
  1485.     case '{':
  1486.         if (isDIGIT(d[1]))
  1487.         e = d;
  1488.         else
  1489.         goto defchar;
  1490.         break;
  1491.     case '.': case '[': case '$': case '(': case ')': case '|': case '+':
  1492.     case '^':
  1493.         e = d;
  1494.         break;
  1495.     case '\\':
  1496.         if (d[1] && index("wWbB0123456789sSdDlLuUExc",d[1])) {
  1497.         e = d;
  1498.         break;
  1499.         }
  1500.         (void)bcopy(d+1,d,e-d);
  1501.         e--;
  1502.         switch(*d) {
  1503.         case 'n':
  1504.         *d = '\n';
  1505.         break;
  1506.         case 't':
  1507.         *d = '\t';
  1508.         break;
  1509.         case 'f':
  1510.         *d = '\f';
  1511.         break;
  1512.         case 'r':
  1513.         *d = '\r';
  1514.         break;
  1515.         case 'e':
  1516.         *d = '\033';
  1517.         break;
  1518.         case 'a':
  1519.         *d = '\007';
  1520.         break;
  1521.         }
  1522.         /* FALL THROUGH */
  1523.     default:
  1524.       defchar:
  1525.         if (d[1] == '*' || (d[1] == '{' && d[2] == '0') || d[1] == '?') {
  1526.         e = d;
  1527.         break;
  1528.         }
  1529.         d++;
  1530.     }
  1531.     }
  1532.     if (d == t) {
  1533.     str_free(tmpstr);
  1534.     return;
  1535.     }
  1536.     *d = '\0';
  1537.     tmpstr->str_cur = d - t;
  1538.     if (d == t+len)
  1539.     spat->spat_flags |= SPAT_ALL;
  1540.     if (*origstring != '^')
  1541.     spat->spat_flags |= SPAT_SCANFIRST;
  1542.     spat->spat_short = tmpstr;
  1543.     spat->spat_slen = d - t;
  1544. }
  1545.  
  1546. char *
  1547. scanpat(s)
  1548. register char *s;
  1549. {
  1550.     register SPAT *spat;
  1551.     register char *d;
  1552.     register char *e;
  1553.     int len;
  1554.     SPAT savespat;
  1555.     STR *str = Str_new(93,0);
  1556.     char delim;
  1557.  
  1558.     Newz(801,spat,1,SPAT);
  1559.     spat->spat_next = curstash->tbl_spatroot;    /* link into spat list */
  1560.     curstash->tbl_spatroot = spat;
  1561.  
  1562.     switch (*s++) {
  1563.     case 'm':
  1564.     s++;
  1565.     break;
  1566.     case '/':
  1567.     break;
  1568.     case '?':
  1569.     spat->spat_flags |= SPAT_ONCE;
  1570.     break;
  1571.     default:
  1572.     fatal("panic: scanpat");
  1573.     }
  1574.     s = str_append_till(str,s,bufend,s[-1],patleave);
  1575.     if (s >= bufend) {
  1576.     str_free(str);
  1577.     yyerror("Search pattern not terminated");
  1578.     yylval.arg = Nullarg;
  1579.     return s;
  1580.     }
  1581.     delim = *s++;
  1582.     while (*s == 'i' || *s == 'o' || *s == 'g') {
  1583.     if (*s == 'i') {
  1584.         s++;
  1585.         sawi = TRUE;
  1586.         spat->spat_flags |= SPAT_FOLD;
  1587.     }
  1588.     if (*s == 'o') {
  1589.         s++;
  1590.         spat->spat_flags |= SPAT_KEEP;
  1591.     }
  1592.     if (*s == 'g') {
  1593.         s++;
  1594.         spat->spat_flags |= SPAT_GLOBAL;
  1595.     }
  1596.     }
  1597.     len = str->str_cur;
  1598.     e = str->str_ptr + len;
  1599.     if (delim == '\'')
  1600.     d = e;
  1601.     else
  1602.     d = str->str_ptr;
  1603.     for (; d < e; d++) {
  1604.     if (*d == '\\')
  1605.         d++;
  1606.     else if ((*d == '$' && d[1] && d[1] != '|' && d[1] != ')') ||
  1607.          (*d == '@')) {
  1608.         register ARG *arg;
  1609.  
  1610.         spat->spat_runtime = arg = op_new(1);
  1611.         arg->arg_type = O_ITEM;
  1612.         arg[1].arg_type = A_DOUBLE;
  1613.         arg[1].arg_ptr.arg_str = str_smake(str);
  1614.         d = scanident(d,bufend,buf);
  1615.         (void)stabent(buf,TRUE);        /* make sure it's created */
  1616.         for (; d < e; d++) {
  1617.         if (*d == '\\')
  1618.             d++;
  1619.         else if (*d == '$' && d[1] && d[1] != '|' && d[1] != ')') {
  1620.             d = scanident(d,bufend,buf);
  1621.             (void)stabent(buf,TRUE);
  1622.         }
  1623.         else if (*d == '@') {
  1624.             d = scanident(d,bufend,buf);
  1625.             if (strEQ(buf,"ARGV") || strEQ(buf,"ENV") ||
  1626.               strEQ(buf,"SIG") || strEQ(buf,"INC"))
  1627.             (void)stabent(buf,TRUE);
  1628.         }
  1629.         }
  1630.         goto got_pat;        /* skip compiling for now */
  1631.     }
  1632.     }
  1633.     if (spat->spat_flags & SPAT_FOLD)
  1634. #ifdef STRUCTCOPY
  1635.     savespat = *spat;
  1636. #else
  1637.     (void)bcopy((char *)spat, (char *)&savespat, sizeof(SPAT));
  1638. #endif
  1639.     scanconst(spat,str->str_ptr,len);
  1640.     if ((spat->spat_flags & SPAT_ALL) && (spat->spat_flags & SPAT_SCANFIRST)) {
  1641.     fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
  1642.     spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
  1643.         spat->spat_flags & SPAT_FOLD);
  1644.         /* Note that this regexp can still be used if someone says
  1645.          * something like /a/ && s//b/;  so we can't delete it.
  1646.          */
  1647.     }
  1648.     else {
  1649.     if (spat->spat_flags & SPAT_FOLD)
  1650. #ifdef STRUCTCOPY
  1651.         *spat = savespat;
  1652. #else
  1653.         (void)bcopy((char *)&savespat, (char *)spat, sizeof(SPAT));
  1654. #endif
  1655.     if (spat->spat_short)
  1656.         fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
  1657.     spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
  1658.         spat->spat_flags & SPAT_FOLD);
  1659.     hoistmust(spat);
  1660.     }
  1661.   got_pat:
  1662.     str_free(str);
  1663.     yylval.arg = make_match(O_MATCH,stab2arg(A_STAB,defstab),spat);
  1664.     return s;
  1665. }
  1666.  
  1667. char *
  1668. scansubst(s)
  1669. register char *s;
  1670. {
  1671.     register SPAT *spat;
  1672.     register char *d;
  1673.     register char *e;
  1674.     int len;
  1675.     STR *str = Str_new(93,0);
  1676.  
  1677.     Newz(802,spat,1,SPAT);
  1678.     spat->spat_next = curstash->tbl_spatroot;    /* link into spat list */
  1679.     curstash->tbl_spatroot = spat;
  1680.  
  1681.     s = str_append_till(str,s+1,bufend,*s,patleave);
  1682.     if (s >= bufend) {
  1683.     str_free(str);
  1684.     yyerror("Substitution pattern not terminated");
  1685.     yylval.arg = Nullarg;
  1686.     return s;
  1687.     }
  1688.     len = str->str_cur;
  1689.     e = str->str_ptr + len;
  1690.     for (d = str->str_ptr; d < e; d++) {
  1691.     if (*d == '\\')
  1692.         d++;
  1693.     else if ((*d == '$' && d[1] && d[1] != '|' && /*(*/ d[1] != ')') ||
  1694.         *d == '@' ) {
  1695.         register ARG *arg;
  1696.  
  1697.         spat->spat_runtime = arg = op_new(1);
  1698.         arg->arg_type = O_ITEM;
  1699.         arg[1].arg_type = A_DOUBLE;
  1700.         arg[1].arg_ptr.arg_str = str_smake(str);
  1701.         d = scanident(d,e,buf);
  1702.         (void)stabent(buf,TRUE);        /* make sure it's created */
  1703.         for (; *d; d++) {
  1704.         if (*d == '$' && d[1] && d[-1] != '\\' && d[1] != '|') {
  1705.             d = scanident(d,e,buf);
  1706.             (void)stabent(buf,TRUE);
  1707.         }
  1708.         else if (*d == '@' && d[-1] != '\\') {
  1709.             d = scanident(d,e,buf);
  1710.             if (strEQ(buf,"ARGV") || strEQ(buf,"ENV") ||
  1711.               strEQ(buf,"SIG") || strEQ(buf,"INC"))
  1712.             (void)stabent(buf,TRUE);
  1713.         }
  1714.         }
  1715.         goto get_repl;        /* skip compiling for now */
  1716.     }
  1717.     }
  1718.     scanconst(spat,str->str_ptr,len);
  1719. get_repl:
  1720.     s = scanstr(s);
  1721.     if (s >= bufend) {
  1722.     str_free(str);
  1723.     yyerror("Substitution replacement not terminated");
  1724.     yylval.arg = Nullarg;
  1725.     return s;
  1726.     }
  1727.     spat->spat_repl = yylval.arg;
  1728.     if ((spat->spat_repl[1].arg_type & A_MASK) == A_SINGLE)
  1729.     spat->spat_flags |= SPAT_CONST;
  1730.     else if ((spat->spat_repl[1].arg_type & A_MASK) == A_DOUBLE) {
  1731.     STR *tmpstr;
  1732.     register char *t;
  1733.  
  1734.     spat->spat_flags |= SPAT_CONST;
  1735.     tmpstr = spat->spat_repl[1].arg_ptr.arg_str;
  1736.     e = tmpstr->str_ptr + tmpstr->str_cur;
  1737.     for (t = tmpstr->str_ptr; t < e; t++) {
  1738.         if (*t == '$' && t[1] && (index("`'&+0123456789",t[1]) ||
  1739.           (t[1] == '{' /*}*/ && isDIGIT(t[2])) ))
  1740.         spat->spat_flags &= ~SPAT_CONST;
  1741.     }
  1742.     }
  1743.     while (*s == 'g' || *s == 'i' || *s == 'e' || *s == 'o') {
  1744.     if (*s == 'e') {
  1745.         s++;
  1746.         if ((spat->spat_repl[1].arg_type & A_MASK) == A_DOUBLE)
  1747.         spat->spat_repl[1].arg_type = A_SINGLE;
  1748.         spat->spat_repl = make_op(
  1749.         (spat->spat_repl[1].arg_type == A_SINGLE ? O_EVALONCE : O_EVAL),
  1750.         2,
  1751.         spat->spat_repl,
  1752.         Nullarg,
  1753.         Nullarg);
  1754.         spat->spat_flags &= ~SPAT_CONST;
  1755.     }
  1756.     if (*s == 'g') {
  1757.         s++;
  1758.         spat->spat_flags |= SPAT_GLOBAL;
  1759.     }
  1760.     if (*s == 'i') {
  1761.         s++;
  1762.         sawi = TRUE;
  1763.         spat->spat_flags |= SPAT_FOLD;
  1764.         if (!(spat->spat_flags & SPAT_SCANFIRST)) {
  1765.         str_free(spat->spat_short);    /* anchored opt doesn't do */
  1766.         spat->spat_short = Nullstr;    /* case insensitive match */
  1767.         spat->spat_slen = 0;
  1768.         }
  1769.     }
  1770.     if (*s == 'o') {
  1771.         s++;
  1772.         spat->spat_flags |= SPAT_KEEP;
  1773.     }
  1774.     }
  1775.     if (spat->spat_short && (spat->spat_flags & SPAT_SCANFIRST))
  1776.     fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
  1777.     if (!spat->spat_runtime) {
  1778.     spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
  1779.       spat->spat_flags & SPAT_FOLD);
  1780.     hoistmust(spat);
  1781.     }
  1782.     yylval.arg = make_match(O_SUBST,stab2arg(A_STAB,defstab),spat);
  1783.     str_free(str);
  1784.     return s;
  1785. }
  1786.  
  1787. void
  1788. hoistmust(spat)
  1789. register SPAT *spat;
  1790. {
  1791.     if (!spat->spat_short && spat->spat_regexp->regstart &&
  1792.     (!spat->spat_regexp->regmust || spat->spat_regexp->reganch & ROPT_ANCH)
  1793.        ) {
  1794.     if (!(spat->spat_regexp->reganch & ROPT_ANCH))
  1795.         spat->spat_flags |= SPAT_SCANFIRST;
  1796.     else if (spat->spat_flags & SPAT_FOLD)
  1797.         return;
  1798.     spat->spat_short = str_smake(spat->spat_regexp->regstart);
  1799.     }
  1800.     else if (spat->spat_regexp->regmust) {/* is there a better short-circuit? */
  1801.     if (spat->spat_short &&
  1802.       str_eq(spat->spat_short,spat->spat_regexp->regmust))
  1803.     {
  1804.         if (spat->spat_flags & SPAT_SCANFIRST) {
  1805.         str_free(spat->spat_short);
  1806.         spat->spat_short = Nullstr;
  1807.         }
  1808.         else {
  1809.         str_free(spat->spat_regexp->regmust);
  1810.         spat->spat_regexp->regmust = Nullstr;
  1811.         return;
  1812.         }
  1813.     }
  1814.     if (!spat->spat_short ||    /* promote the better string */
  1815.       ((spat->spat_flags & SPAT_SCANFIRST) &&
  1816.        (spat->spat_short->str_cur < spat->spat_regexp->regmust->str_cur) )){
  1817.         str_free(spat->spat_short);        /* ok if null */
  1818.         spat->spat_short = spat->spat_regexp->regmust;
  1819.         spat->spat_regexp->regmust = Nullstr;
  1820.         spat->spat_flags |= SPAT_SCANFIRST;
  1821.     }
  1822.     }
  1823. }
  1824.  
  1825. char *
  1826. expand_charset(s,len,retlen)
  1827. register char *s;
  1828. int len;
  1829. int *retlen;
  1830. {
  1831.     char t[520];
  1832.     register char *d = t;
  1833.     register int i;
  1834.     register char *send = s + len;
  1835.  
  1836.     while (s < send && d - t <= 256) {
  1837.     if (s[1] == '-' && s+2 < send) {
  1838.         for (i = (s[0] & 0377); i <= (s[2] & 0377); i++)
  1839.         *d++ = i;
  1840.         s += 3;
  1841.     }
  1842.     else
  1843.         *d++ = *s++;
  1844.     }
  1845.     *d = '\0';
  1846.     *retlen = d - t;
  1847.     return nsavestr(t,d-t);
  1848. }
  1849.  
  1850. char *
  1851. scantrans(s)
  1852. register char *s;
  1853. {
  1854.     ARG *arg =
  1855.     l(make_op(O_TRANS,2,stab2arg(A_STAB,defstab),Nullarg,Nullarg));
  1856.     register char *t;
  1857.     register char *r;
  1858.     register short *tbl;
  1859.     register int i;
  1860.     register int j;
  1861.     int tlen, rlen;
  1862.     int squash;
  1863.     int delete;
  1864.     int complement;
  1865.  
  1866.     New(803,tbl,256,short);
  1867.     arg[2].arg_type = A_NULL;
  1868.     arg[2].arg_ptr.arg_cval = (char*) tbl;
  1869.     s = scanstr(s);
  1870.     if (s >= bufend) {
  1871.     yyerror("Translation pattern not terminated");
  1872.     yylval.arg = Nullarg;
  1873.     return s;
  1874.     }
  1875.     t = expand_charset(yylval.arg[1].arg_ptr.arg_str->str_ptr,
  1876.     yylval.arg[1].arg_ptr.arg_str->str_cur,&tlen);
  1877.     arg_free(yylval.arg);
  1878.     s = scanstr(s-1);
  1879.     if (s >= bufend) {
  1880.     yyerror("Translation replacement not terminated");
  1881.     yylval.arg = Nullarg;
  1882.     return s;
  1883.     }
  1884.     complement = delete = squash = 0;
  1885.     while (*s == 'c' || *s == 'd' || *s == 's') {
  1886.     if (*s == 'c')
  1887.         complement = 1;
  1888.     else if (*s == 'd')
  1889.         delete = 2;
  1890.     else
  1891.         squash = 1;
  1892.     s++;
  1893.     }
  1894.     r = expand_charset(yylval.arg[1].arg_ptr.arg_str->str_ptr,
  1895.     yylval.arg[1].arg_ptr.arg_str->str_cur,&rlen);
  1896.     arg_free(yylval.arg);
  1897.     arg[2].arg_len = delete|squash;
  1898.     yylval.arg = arg;
  1899.     if (!rlen && !delete) {
  1900.     Safefree(r);
  1901.     r = t; rlen = tlen;
  1902.     }
  1903.     if (complement) {
  1904.     Zero(tbl, 256, short);
  1905.     for (i = 0; i < tlen; i++)
  1906.         tbl[t[i] & 0377] = -1;
  1907.     for (i = 0, j = 0; i < 256; i++) {
  1908.         if (!tbl[i]) {
  1909.         if (j >= rlen) {
  1910.             if (delete)
  1911.             tbl[i] = -2;
  1912.             else
  1913.             tbl[i] = r[j-1];
  1914.         }
  1915.         else
  1916.             tbl[i] = r[j++];
  1917.         }
  1918.     }
  1919.     }
  1920.     else {
  1921.     for (i = 0; i < 256; i++)
  1922.         tbl[i] = -1;
  1923.     for (i = 0, j = 0; i < tlen; i++,j++) {
  1924.         if (j >= rlen) {
  1925.         if (delete) {
  1926.             if (tbl[t[i] & 0377] == -1)
  1927.             tbl[t[i] & 0377] = -2;
  1928.             continue;
  1929.         }
  1930.         --j;
  1931.         }
  1932.         if (tbl[t[i] & 0377] == -1)
  1933.         tbl[t[i] & 0377] = r[j] & 0377;
  1934.     }
  1935.     }
  1936.     if (r != t)
  1937.     Safefree(r);
  1938.     Safefree(t);
  1939.     return s;
  1940. }
  1941.  
  1942. char *
  1943. scanstr(s)
  1944. register char *s;
  1945. {
  1946.     register char term;
  1947.     register char *d;
  1948.     register ARG *arg;
  1949.     register char *send;
  1950.     register bool makesingle = FALSE;
  1951.     register STAB *stab;
  1952.     bool alwaysdollar = FALSE;
  1953.     bool hereis = FALSE;
  1954.     STR *herewas;
  1955.     STR *str;
  1956.     char *leave = "\\$@nrtfbeacx0123456789[{]}lLuUE"; /* which backslash sequences to keep */
  1957.     int len;
  1958.  
  1959.     arg = op_new(1);
  1960.     yylval.arg = arg;
  1961.     arg->arg_type = O_ITEM;
  1962.  
  1963.     switch (*s) {
  1964.     default:            /* a substitution replacement */
  1965.     arg[1].arg_type = A_DOUBLE;
  1966.     makesingle = TRUE;    /* maybe disable runtime scanning */
  1967.     term = *s;
  1968.     if (term == '\'')
  1969.         leave = Nullch;
  1970.     goto snarf_it;
  1971.     case '0':
  1972.     {
  1973.         unsigned long i;
  1974.         int shift;
  1975.  
  1976.         arg[1].arg_type = A_SINGLE;
  1977.         if (s[1] == 'x') {
  1978.         shift = 4;
  1979.         s += 2;
  1980.         }
  1981.         else if (s[1] == '.')
  1982.         goto decimal;
  1983.         else
  1984.         shift = 3;
  1985.         i = 0;
  1986.         for (;;) {
  1987.         switch (*s) {
  1988.         default:
  1989.             goto out;
  1990.         case '_':
  1991.             s++;
  1992.             break;
  1993.         case '8': case '9':
  1994.             if (shift != 4)
  1995.             yyerror("Illegal octal digit");
  1996.             /* FALL THROUGH */
  1997.         case '0': case '1': case '2': case '3': case '4':
  1998.         case '5': case '6': case '7':
  1999.             i <<= shift;
  2000.             i += *s++ & 15;
  2001.             break;
  2002.         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
  2003.         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
  2004.             if (shift != 4)
  2005.             goto out;
  2006.             i <<= 4;
  2007.             i += (*s++ & 7) + 9;
  2008.             break;
  2009.         }
  2010.         }
  2011.       out:
  2012.         str = Str_new(92,0);
  2013.         str_numset(str,(double)i);
  2014.         if (str->str_ptr) {
  2015.         Safefree(str->str_ptr);
  2016.         str->str_ptr = Nullch;
  2017.         str->str_len = str->str_cur = 0;
  2018.         }
  2019.         arg[1].arg_ptr.arg_str = str;
  2020.     }
  2021.     break;
  2022.     case '1': case '2': case '3': case '4': case '5':
  2023.     case '6': case '7': case '8': case '9': case '.':
  2024.       decimal:
  2025.     arg[1].arg_type = A_SINGLE;
  2026.     d = tokenbuf;
  2027.     while (isDIGIT(*s) || *s == '_') {
  2028.         if (*s == '_')
  2029.         s++;
  2030.         else
  2031.         *d++ = *s++;
  2032.     }
  2033.     if (*s == '.' && s[1] && index("0123456789eE ;",s[1])) {
  2034.         *d++ = *s++;
  2035.         while (isDIGIT(*s) || *s == '_') {
  2036.         if (*s == '_')
  2037.             s++;
  2038.         else
  2039.             *d++ = *s++;
  2040.         }
  2041.     }
  2042.     if (*s && index("eE",*s) && index("+-0123456789",s[1])) {
  2043.         *d++ = *s++;
  2044.         if (*s == '+' || *s == '-')
  2045.         *d++ = *s++;
  2046.         while (isDIGIT(*s))
  2047.         *d++ = *s++;
  2048.     }
  2049.     *d = '\0';
  2050.     str = Str_new(92,0);
  2051.     str_numset(str,atof(tokenbuf));
  2052.     if (str->str_ptr) {
  2053.         Safefree(str->str_ptr);
  2054.         str->str_ptr = Nullch;
  2055.         str->str_len = str->str_cur = 0;
  2056.     }
  2057.     arg[1].arg_ptr.arg_str = str;
  2058.     break;
  2059.     case '<':
  2060.     if (*++s == '<') {
  2061.         hereis = TRUE;
  2062.         d = tokenbuf;
  2063.         if (!rsfp)
  2064.         *d++ = '\n';
  2065.         if (*++s && index("`'\"",*s)) {
  2066.         term = *s++;
  2067.         s = cpytill(d,s,bufend,term,&len);
  2068.         if (s < bufend)
  2069.             s++;
  2070.         d += len;
  2071.         }
  2072.         else {
  2073.         if (*s == '\\')
  2074.             s++, term = '\'';
  2075.         else
  2076.             term = '"';
  2077.         while (isALNUM(*s))
  2078.             *d++ = *s++;
  2079.         }                /* assuming tokenbuf won't clobber */
  2080.         *d++ = '\n';
  2081.         *d = '\0';
  2082.         len = d - tokenbuf;
  2083.         d = "\n";
  2084.         if (rsfp || !(d=ninstr(s,bufend,d,d+1)))
  2085.         herewas = str_make(s,bufend-s);
  2086.         else
  2087.         s--, herewas = str_make(s,d-s);
  2088.         s += herewas->str_cur;
  2089.         if (term == '\'')
  2090.         goto do_single;
  2091.         if (term == '`')
  2092.         goto do_back;
  2093.         goto do_double;
  2094.     }
  2095.     d = tokenbuf;
  2096.     s = cpytill(d,s,bufend,'>',&len);
  2097.     if (s < bufend)
  2098.         s++;
  2099.     if (*d == '$') d++;
  2100.     while (*d && (isALNUM(*d) || *d == '\''))
  2101.         d++;
  2102.     if (d - tokenbuf != len) {
  2103.         d = tokenbuf;
  2104.         arg[1].arg_type = A_GLOB;
  2105.         d = nsavestr(d,len);
  2106.         arg[1].arg_ptr.arg_stab = stab = genstab();
  2107.         stab_io(stab) = stio_new();
  2108.         stab_val(stab) = str_make(d,len);
  2109.         Safefree(d);
  2110.         set_csh();
  2111.     }
  2112.     else {
  2113.         d = tokenbuf;
  2114.         if (!len)
  2115.         (void)strcpy(d,"ARGV");
  2116.         if (*d == '$') {
  2117.         arg[1].arg_type = A_INDREAD;
  2118.         arg[1].arg_ptr.arg_stab = stabent(d+1,TRUE);
  2119.         }
  2120.         else {
  2121.         arg[1].arg_type = A_READ;
  2122.         arg[1].arg_ptr.arg_stab = stabent(d,TRUE);
  2123.         if (!stab_io(arg[1].arg_ptr.arg_stab))
  2124.             stab_io(arg[1].arg_ptr.arg_stab) = stio_new();
  2125.         if (strEQ(d,"ARGV")) {
  2126.             (void)aadd(arg[1].arg_ptr.arg_stab);
  2127.             stab_io(arg[1].arg_ptr.arg_stab)->flags |=
  2128.               IOF_ARGV|IOF_START;
  2129.         }
  2130.         }
  2131.     }
  2132.     break;
  2133.  
  2134.     case 'q':
  2135.     s++;
  2136.     if (*s == 'q') {
  2137.         s++;
  2138.         goto do_double;
  2139.     }
  2140.     if (*s == 'x') {
  2141.         s++;
  2142.         goto do_back;
  2143.     }
  2144.     /* FALL THROUGH */
  2145.     case '\'':
  2146.       do_single:
  2147.     term = *s;
  2148.     arg[1].arg_type = A_SINGLE;
  2149.     leave = Nullch;
  2150.     goto snarf_it;
  2151.  
  2152.     case '"': 
  2153.       do_double:
  2154.     term = *s;
  2155.     arg[1].arg_type = A_DOUBLE;
  2156.     makesingle = TRUE;    /* maybe disable runtime scanning */
  2157.     alwaysdollar = TRUE;    /* treat $) and $| as variables */
  2158.     goto snarf_it;
  2159.     case '`':
  2160.       do_back:
  2161.     term = *s;
  2162.     arg[1].arg_type = A_BACKTICK;
  2163.     set_csh();
  2164.     alwaysdollar = TRUE;    /* treat $) and $| as variables */
  2165.       snarf_it:
  2166.     {
  2167.         STR *tmpstr;
  2168.         char *tmps;
  2169.  
  2170.         CLINE;
  2171.         multi_start = curcmd->c_line;
  2172.         if (hereis)
  2173.         multi_open = multi_close = '<';
  2174.         else {
  2175.         multi_open = term;
  2176.         if (term && (tmps = index("([{< )]}> )]}>",term)))
  2177.             term = tmps[5];
  2178.         multi_close = term;
  2179.         }
  2180.         tmpstr = Str_new(87,80);
  2181.         if (hereis) {
  2182.         term = *tokenbuf;
  2183.         if (!rsfp) {
  2184.             d = s;
  2185.             while (s < bufend &&
  2186.               (*s != term || bcmp(s,tokenbuf,len) != 0) ) {
  2187.             if (*s++ == '\n')
  2188.                 curcmd->c_line++;
  2189.             }
  2190.             if (s >= bufend) {
  2191.             curcmd->c_line = multi_start;
  2192.             fatal("EOF in string");
  2193.             }
  2194.             str_nset(tmpstr,d+1,s-d);
  2195.             s += len - 1;
  2196.             str_ncat(herewas,s,bufend-s);
  2197.             str_replace(linestr,herewas);
  2198.             oldoldbufptr = oldbufptr = bufptr = s = str_get(linestr);
  2199.             bufend = linestr->str_ptr + linestr->str_cur;
  2200.             hereis = FALSE;
  2201.         }
  2202.         else
  2203.             str_nset(tmpstr,"",0);   /* avoid "uninitialized" warning */
  2204.         }
  2205.         else
  2206.         s = str_append_till(tmpstr,s+1,bufend,term,leave);
  2207.         while (s >= bufend) {    /* multiple line string? */
  2208.         if (!rsfp ||
  2209.          !(oldoldbufptr = oldbufptr = s = str_gets(linestr, rsfp, 0))) {
  2210.             curcmd->c_line = multi_start;
  2211.             fatal("EOF in string");
  2212.         }
  2213.         curcmd->c_line++;
  2214.         if (perldb) {
  2215.             STR *str = Str_new(88,0);
  2216.  
  2217.             str_sset(str,linestr);
  2218.             astore(stab_xarray(curcmd->c_filestab),
  2219.               (int)curcmd->c_line,str);
  2220.         }
  2221.         bufend = linestr->str_ptr + linestr->str_cur;
  2222.         if (hereis) {
  2223.             if (*s == term && bcmp(s,tokenbuf,len) == 0) {
  2224.             s = bufend - 1;
  2225.             *s = ' ';
  2226.             str_scat(linestr,herewas);
  2227.             bufend = linestr->str_ptr + linestr->str_cur;
  2228.             }
  2229.             else {
  2230.             s = bufend;
  2231.             str_scat(tmpstr,linestr);
  2232.             }
  2233.         }
  2234.         else
  2235.             s = str_append_till(tmpstr,s,bufend,term,leave);
  2236.         }
  2237.         multi_end = curcmd->c_line;
  2238.         s++;
  2239.         if (tmpstr->str_cur + 5 < tmpstr->str_len) {
  2240.         tmpstr->str_len = tmpstr->str_cur + 1;
  2241.         Renew(tmpstr->str_ptr, tmpstr->str_len, char);
  2242.         }
  2243.         if ((arg[1].arg_type & A_MASK) == A_SINGLE) {
  2244.         arg[1].arg_ptr.arg_str = tmpstr;
  2245.         break;
  2246.         }
  2247.         tmps = s;
  2248.         s = tmpstr->str_ptr;
  2249.         send = s + tmpstr->str_cur;
  2250.         while (s < send) {        /* see if we can make SINGLE */
  2251.         if (*s == '\\' && s[1] && isDIGIT(s[1]) && !isDIGIT(s[2]) &&
  2252.           !alwaysdollar && s[1] != '0')
  2253.             *s = '$';        /* grandfather \digit in subst */
  2254.         if ((*s == '$' || *s == '@') && s+1 < send &&
  2255.           (alwaysdollar || (s[1] != ')' && s[1] != '|'))) {
  2256.             makesingle = FALSE;    /* force interpretation */
  2257.         }
  2258.         else if (*s == '\\' && s+1 < send) {
  2259.             if (index("lLuUE",s[1]))
  2260.             makesingle = FALSE;
  2261.             s++;
  2262.         }
  2263.         s++;
  2264.         }
  2265.         s = d = tmpstr->str_ptr;    /* assuming shrinkage only */
  2266.         while (s < send) {
  2267.         if ((*s == '$' && s+1 < send &&
  2268.             (alwaysdollar || /*(*/ (s[1] != ')' && s[1] != '|')) ) ||
  2269.             (*s == '@' && s+1 < send) ) {
  2270.             if (s[1] == '#' && (isALPHA(s[2]) || s[2] == '_'))
  2271.             *d++ = *s++;
  2272.             len = scanident(s,send,tokenbuf) - s;
  2273.             if (*s == '$' || strEQ(tokenbuf,"ARGV")
  2274.               || strEQ(tokenbuf,"ENV")
  2275.               || strEQ(tokenbuf,"SIG")
  2276.               || strEQ(tokenbuf,"INC") )
  2277.             (void)stabent(tokenbuf,TRUE); /* make sure it exists */
  2278.             while (len--)
  2279.             *d++ = *s++;
  2280.             continue;
  2281.         }
  2282.         else if (*s == '\\' && s+1 < send) {
  2283.             s++;
  2284.             switch (*s) {
  2285.             default:
  2286.             if (!makesingle && (!leave || (*s && index(leave,*s))))
  2287.                 *d++ = '\\';
  2288.             *d++ = *s++;
  2289.             continue;
  2290.             case '0': case '1': case '2': case '3':
  2291.             case '4': case '5': case '6': case '7':
  2292.             *d++ = scanoct(s, 3, &len);
  2293.             s += len;
  2294.             continue;
  2295.             case 'x':
  2296.             *d++ = scanhex(++s, 2, &len);
  2297.             s += len;
  2298.             continue;
  2299.             case 'c':
  2300.             s++;
  2301.             *d = *s++;
  2302.             if (isLOWER(*d))
  2303.                 *d = toupper(*d);
  2304.             *d++ ^= 64;
  2305.             continue;
  2306.             case 'b':
  2307.             *d++ = '\b';
  2308.             break;
  2309.             case 'n':
  2310.             *d++ = '\n';
  2311.             break;
  2312.             case 'r':
  2313.             *d++ = '\r';
  2314.             break;
  2315.             case 'f':
  2316.             *d++ = '\f';
  2317.             break;
  2318.             case 't':
  2319.             *d++ = '\t';
  2320.             break;
  2321.             case 'e':
  2322.             *d++ = '\033';
  2323.             break;
  2324.             case 'a':
  2325.             *d++ = '\007';
  2326.             break;
  2327.             }
  2328.             s++;
  2329.             continue;
  2330.         }
  2331.         *d++ = *s++;
  2332.         }
  2333.         *d = '\0';
  2334.  
  2335.         if ((arg[1].arg_type & A_MASK) == A_DOUBLE && makesingle)
  2336.             arg[1].arg_type = A_SINGLE;    /* now we can optimize on it */
  2337.  
  2338.         tmpstr->str_cur = d - tmpstr->str_ptr;
  2339.         arg[1].arg_ptr.arg_str = tmpstr;
  2340.         s = tmps;
  2341.         break;
  2342.     }
  2343.     }
  2344.     if (hereis)
  2345.     str_free(herewas);
  2346.     return s;
  2347. }
  2348.  
  2349. FCMD *
  2350. load_format()
  2351. {
  2352.     FCMD froot;
  2353.     FCMD *flinebeg;
  2354.     char *eol;
  2355.     register FCMD *fprev = &froot;
  2356.     register FCMD *fcmd;
  2357.     register char *s;
  2358.     register char *t;
  2359.     register STR *str;
  2360.     bool noblank;
  2361.     bool repeater;
  2362.  
  2363.     Zero(&froot, 1, FCMD);
  2364.     s = bufptr;
  2365.     while (s < bufend || (rsfp && (s = str_gets(linestr,rsfp, 0)) != Nullch)) {
  2366.     curcmd->c_line++;
  2367.     if (in_eval && !rsfp) {
  2368.         eol = index(s,'\n');
  2369.         if (!eol++)
  2370.         eol = bufend;
  2371.     }
  2372.     else
  2373.         eol = bufend = linestr->str_ptr + linestr->str_cur;
  2374.     if (perldb) {
  2375.         STR *tmpstr = Str_new(89,0);
  2376.  
  2377.         str_nset(tmpstr, s, eol-s);
  2378.         astore(stab_xarray(curcmd->c_filestab), (int)curcmd->c_line,tmpstr);
  2379.     }
  2380.     if (*s == '.') {
  2381.         /*SUPPRESS 530*/
  2382.         for (t = s+1; *t == ' ' || *t == '\t'; t++) ;
  2383.         if (*t == '\n') {
  2384.         bufptr = s;
  2385.         return froot.f_next;
  2386.         }
  2387.     }
  2388.     if (*s == '#') {
  2389.         s = eol;
  2390.         continue;
  2391.     }
  2392.     flinebeg = Nullfcmd;
  2393.     noblank = FALSE;
  2394.     repeater = FALSE;
  2395.     while (s < eol) {
  2396.         Newz(804,fcmd,1,FCMD);
  2397.         fprev->f_next = fcmd;
  2398.         fprev = fcmd;
  2399.         for (t=s; t < eol && *t != '@' && *t != '^'; t++) {
  2400.         if (*t == '~') {
  2401.             noblank = TRUE;
  2402.             *t = ' ';
  2403.             if (t[1] == '~') {
  2404.             repeater = TRUE;
  2405.             t[1] = ' ';
  2406.             }
  2407.         }
  2408.         }
  2409.         fcmd->f_pre = nsavestr(s, t-s);
  2410.         fcmd->f_presize = t-s;
  2411.         s = t;
  2412.         if (s >= eol) {
  2413.         if (noblank)
  2414.             fcmd->f_flags |= FC_NOBLANK;
  2415.         if (repeater)
  2416.             fcmd->f_flags |= FC_REPEAT;
  2417.         break;
  2418.         }
  2419.         if (!flinebeg)
  2420.         flinebeg = fcmd;        /* start values here */
  2421.         if (*s++ == '^')
  2422.         fcmd->f_flags |= FC_CHOP;    /* for doing text filling */
  2423.         switch (*s) {
  2424.         case '*':
  2425.         fcmd->f_type = F_LINES;
  2426.         *s = '\0';
  2427.         break;
  2428.         case '<':
  2429.         fcmd->f_type = F_LEFT;
  2430.         while (*s == '<')
  2431.             s++;
  2432.         break;
  2433.         case '>':
  2434.         fcmd->f_type = F_RIGHT;
  2435.         while (*s == '>')
  2436.             s++;
  2437.         break;
  2438.         case '|':
  2439.         fcmd->f_type = F_CENTER;
  2440.         while (*s == '|')
  2441.             s++;
  2442.         break;
  2443.         case '#':
  2444.         case '.':
  2445.         /* Catch the special case @... and handle it as a string
  2446.            field. */
  2447.         if (*s == '.' && s[1] == '.') {
  2448.             goto default_format;
  2449.         }
  2450.         fcmd->f_type = F_DECIMAL;
  2451.         {
  2452.             char *p;
  2453.  
  2454.             /* Read a format in the form @####.####, where either group
  2455.                of ### may be empty, or the final .### may be missing. */
  2456.             while (*s == '#')
  2457.             s++;
  2458.             if (*s == '.') {
  2459.             s++;
  2460.             p = s;
  2461.             while (*s == '#')
  2462.                 s++;
  2463.             fcmd->f_decimals = s-p;
  2464.             fcmd->f_flags |= FC_DP;
  2465.             } else {
  2466.             fcmd->f_decimals = 0;
  2467.             }
  2468.         }
  2469.         break;
  2470.         default:
  2471.         default_format:
  2472.         fcmd->f_type = F_LEFT;
  2473.         break;
  2474.         }
  2475.         if (fcmd->f_flags & FC_CHOP && *s == '.') {
  2476.         fcmd->f_flags |= FC_MORE;
  2477.         while (*s == '.')
  2478.             s++;
  2479.         }
  2480.         fcmd->f_size = s-t;
  2481.     }
  2482.     if (flinebeg) {
  2483.       again:
  2484.         if (s >= bufend &&
  2485.           (!rsfp || (s = str_gets(linestr, rsfp, 0)) == Nullch) )
  2486.         goto badform;
  2487.         curcmd->c_line++;
  2488.         if (in_eval && !rsfp) {
  2489.         eol = index(s,'\n');
  2490.         if (!eol++)
  2491.             eol = bufend;
  2492.         }
  2493.         else
  2494.         eol = bufend = linestr->str_ptr + linestr->str_cur;
  2495.         if (perldb) {
  2496.         STR *tmpstr = Str_new(90,0);
  2497.  
  2498.         str_nset(tmpstr, s, eol-s);
  2499.         astore(stab_xarray(curcmd->c_filestab),
  2500.             (int)curcmd->c_line,tmpstr);
  2501.         }
  2502.         if (strnEQ(s,".\n",2)) {
  2503.         bufptr = s;
  2504.         yyerror("Missing values line");
  2505.         return froot.f_next;
  2506.         }
  2507.         if (*s == '#') {
  2508.         s = eol;
  2509.         goto again;
  2510.         }
  2511.         str = flinebeg->f_unparsed = Str_new(91,eol - s);
  2512.         str->str_u.str_hash = curstash;
  2513.         str_nset(str,"(",1);
  2514.         flinebeg->f_line = curcmd->c_line;
  2515.         eol[-1] = '\0';
  2516.         if (!flinebeg->f_next->f_type || index(s, ',')) {
  2517.         eol[-1] = '\n';
  2518.         str_ncat(str, s, eol - s - 1);
  2519.         str_ncat(str,",$$);",5);
  2520.         s = eol;
  2521.         }
  2522.         else {
  2523.         eol[-1] = '\n';
  2524.         while (s < eol && isSPACE(*s))
  2525.             s++;
  2526.         t = s;
  2527.         while (s < eol) {
  2528.             switch (*s) {
  2529.             case ' ': case '\t': case '\n': case ';':
  2530.             str_ncat(str, t, s - t);
  2531.             str_ncat(str, "," ,1);
  2532.             while (s < eol && (isSPACE(*s) || *s == ';'))
  2533.                 s++;
  2534.             t = s;
  2535.             break;
  2536.             case '$':
  2537.             str_ncat(str, t, s - t);
  2538.             t = s;
  2539.             s = scanident(s,eol,tokenbuf);
  2540.             str_ncat(str, t, s - t);
  2541.             t = s;
  2542.             if (s < eol && *s && index("$'\"",*s))
  2543.                 str_ncat(str, ",", 1);
  2544.             break;
  2545.             case '"': case '\'':
  2546.             str_ncat(str, t, s - t);
  2547.             t = s;
  2548.             s++;
  2549.             while (s < eol && (*s != *t || s[-1] == '\\'))
  2550.                 s++;
  2551.             if (s < eol)
  2552.                 s++;
  2553.             str_ncat(str, t, s - t);
  2554.             t = s;
  2555.             if (s < eol && *s && index("$'\"",*s))
  2556.                 str_ncat(str, ",", 1);
  2557.             break;
  2558.             default:
  2559.             yyerror("Please use commas to separate fields");
  2560.             }
  2561.         }
  2562.         str_ncat(str,"$$);",4);
  2563.         }
  2564.     }
  2565.     }
  2566.   badform:
  2567.     bufptr = str_get(linestr);
  2568.     yyerror("Format not terminated");
  2569.     return froot.f_next;
  2570. }
  2571.  
  2572. set_csh()
  2573. {
  2574. #ifdef CSH
  2575.     if (!cshlen)
  2576.     cshlen = strlen(cshname);
  2577. #endif
  2578. }
  2579.